﻿Imports System.Reflection
Imports System.Linq.Expressions

Namespace Load

    ''' <summary>
    ''' モデルローダー
    ''' </summary>
    ''' <remarks></remarks>
    Public Class ModelLoader
        Implements IFromQueryRoot(Of ModelLoader)

        ''' <summary>
        ''' コンストラクタ
        ''' </summary>
        ''' <param name="cn">コネクション</param>
        ''' <param name="prefix">パラメータ接頭語</param>
        ''' <remarks></remarks>
        Public Sub New(ByVal cn As IDbConnection, ByVal prefix As String)
            _connection = cn
            _parameterPrefix = prefix
            Me.ResetQueryType()
        End Sub

        ''' <summary>
        ''' コンストラクタ
        ''' </summary>
        ''' <param name="trn">トランザクション</param>
        ''' <param name="prefix">パラメータ接頭語</param>
        ''' <remarks></remarks>
        Public Sub New(ByVal trn As IDbTransaction, ByVal prefix As String)
            _connection = trn.Connection
            _transaction = trn
            _parameterPrefix = prefix
            Me.ResetQueryType()
        End Sub

#Region "プロパティ"
        Private _connection As IDbConnection
        ''' <summary>
        ''' コネクション
        ''' </summary>
        ''' <value></value>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public ReadOnly Property Connection As IDbConnection
            Get
                Return _connection
            End Get
        End Property

        ''' <summary>
        ''' コネクションを再設定します
        ''' </summary>
        ''' <param name="value"></param>
        ''' <remarks></remarks>
        Friend Sub SetConnection(value As IDbConnection)
            _connection = value
        End Sub

        Private _transaction As IDbTransaction
        ''' <summary>
        ''' トランザクション
        ''' </summary>
        ''' <value></value>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public ReadOnly Property Transaction As IDbTransaction
            Get
                Return _transaction
            End Get
        End Property

        Protected _parameterPrefix As String
        ''' <summary>
        ''' パラメータ接頭語
        ''' </summary>
        ''' <value></value>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public ReadOnly Property ParameterPrefix As String
            Get
                Return _parameterPrefix
            End Get
        End Property

        ''' <summary>
        ''' インスタンス辞書
        ''' </summary>
        ''' <value></value>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Friend Property KeyDictionary As New Dictionary(Of String, ModelCache)

        ''' <summary>
        ''' マッピングを除外する親プロパティ
        ''' </summary>
        ''' <value></value>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Friend Property MappingIgnoreProperty As PropertyInfo
#End Region

#Region "From"
        ''' <summary>
        ''' クエリタイプ初期値
        ''' </summary>
        ''' <value></value>
        ''' <returns></returns>
        ''' <remarks>リセット用</remarks>
        Public Shared Property DefaultQueryType As QueryType = QueryType.Batch

        ''' <summary>
        ''' カスケード上限初期値
        ''' </summary>
        ''' <value></value>
        ''' <returns></returns>
        ''' <remarks>リセット用</remarks>
        Public Shared Property DefaultCascadeLimit As Integer = 0

        ''' <summary>
        ''' 外部結合可否初期値
        ''' </summary>
        ''' <value></value>
        ''' <returns></returns>
        ''' <remarks>リセット用</remarks>
        Public Shared Property DefaulCanLeftJoin As Boolean = False

        ''' <summary>
        ''' クエリタイプ（作業時）
        ''' </summary>
        ''' <value></value>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Friend Property WorkQueryType As QueryType = QueryType.Batch

        ''' <summary>
        ''' カスケード上限（作業時）
        ''' </summary>
        ''' <value></value>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Friend Property WorkCascadeLevel As Integer

        ''' <summary>
        ''' 外部結合可否（作業時）
        ''' </summary>
        ''' <value></value>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Friend Property WorkCanLeftJoin As Boolean

        ''' <summary>
        ''' クエリー設定を初期状態に戻します
        ''' </summary>
        ''' <remarks></remarks>
        Sub ResetQueryType() Implements IQueryRoot(Of Kairyu.Load.ModelLoader).ResetQueryType
            Me.WorkQueryType = ModelLoader.DefaultQueryType
            Me.WorkCascadeLevel = ModelLoader.DefaultCascadeLimit
            Me.WorkCanLeftJoin = ModelLoader.DefaulCanLeftJoin
            Me.MappingIgnoreProperty = Nothing
        End Sub

        ''' <summary>
        ''' バッチで実行します
        ''' </summary>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Function Batch() As ModelLoader Implements IQueryRoot(Of Kairyu.Load.ModelLoader).Batch
            Me.WorkQueryType = Kairyu.Load.QueryType.Batch
            Return Me
        End Function

        ''' <summary>
        ''' イテレートで実行します
        ''' </summary>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Function Iterate() As ModelLoader Implements IQueryRoot(Of Kairyu.Load.ModelLoader).Iterate
            Me.WorkQueryType = Kairyu.Load.QueryType.Iterate
            Return Me
        End Function

        ''' <summary>
        ''' 指定された階層までカスケードして実行します
        ''' </summary>
        ''' <param name="level"></param>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public Function Cascade(level As Integer) As ModelLoader Implements IQueryRoot(Of ModelLoader).Cascade
            Me.WorkCascadeLevel = level
            Return Me
        End Function

        ''' <summary>
        ''' カスケード無制限で実行します
        ''' </summary>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public Function FullCascade() As ModelLoader Implements IQueryRoot(Of ModelLoader).FullCascade
            Me.WorkCascadeLevel = -1
            Return Me
        End Function

        ''' <summary>
        ''' 内部結合のみで実行します
        ''' </summary>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public Function IncludeOuter() As ModelLoader Implements IQueryRoot(Of ModelLoader).IncludeOuter
            Me.WorkCanLeftJoin = True
            Return Me
        End Function

        ''' <summary>
        ''' 外部結合を含んで実行します
        ''' </summary>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public Function InnerOnly() As ModelLoader Implements IQueryRoot(Of ModelLoader).InnerOnly
            Me.WorkCanLeftJoin = False
            Return Me
        End Function

        ''' <summary>
        ''' クエリを取得します
        ''' </summary>
        ''' <typeparam name="SelectT"></typeparam>
        ''' <returns></returns>
        ''' <remarks>
        ''' 任意クエリ用。これに主キー、親、子読み込みなどのパターンを足す予定。
        ''' </remarks>
        Public Function From(Of SelectT)() As Query(Of SelectT) Implements IFromQueryRoot(Of ModelLoader).From
            Return Me.From(Of SelectT)(Nothing)
        End Function

        ''' <summary>
        ''' 検索条件を指定してクエリを取得します
        ''' </summary>
        ''' <typeparam name="T"></typeparam>
        ''' <param name="query"></param>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public Function From(Of T)(query As Query(Of T)) As Query(Of T)
            Dim q As Query(Of T) = Nothing
            If Me.WorkQueryType = QueryType.Batch Then
                'SELECT文にリレーションを使用します。
                q = New Query(Of T)(New BatchQueryProvider(Me))
            Else
                'SELECT文にリレーションを使用しません。
                q = New Query(Of T)(New IterateQueryProvider(Me))
            End If
            '検索条件のコピー
            If query IsNot Nothing AndAlso query.Builders IsNot Nothing Then
                For Each item In query.Builders
                    q.Builders.Add(item)
                Next
            End If
            Return q
        End Function
#End Region

        Public Function ReLoad(Of T)(instance As T) As QueryableList(Of T)
            Return Me.From(Of T).WhereReLoad(instance).Execute
        End Function

        Public Function ReLoad(Of T)(instances As IEnumerable(Of T)) As QueryableList(Of T)
            Return Me.From(Of T).WhereReLoad(instances).Execute
        End Function

        ''' <summary>
        ''' インスタンスから主キー検索条件を設定
        ''' </summary>
        ''' <typeparam name="T"></typeparam>
        ''' <param name="instance"></param>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public Function Load(Of T)(instance As T) As QueryableList(Of T)
            Return Me.From(Of T).WhereLoad(instance).Execute
        End Function

        ''' <summary>
        ''' インスタンスから主キー検索条件を設定
        ''' </summary>
        ''' <typeparam name="T"></typeparam>
        ''' <param name="instances"></param>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public Function Load(Of T)(instances As IEnumerable(Of T)) As QueryableList(Of T)
            Return Me.From(Of T).WhereLoad(instances).Execute
        End Function

    End Class

End Namespace
